package com.cskaoyan.javase.oop.block9.building2;

/**
 * @description: 构造代码块
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * 重点也是难点
 * 构造代码块：
 * 和构造方法类似，处在成员位置的代码块
 * 声明：{}
 * 作用：依赖于构造器的执行而执行，执行构造器就一定执行它，反之不执行
 *   它的作用和构造器类似，是给成员变量赋值用的
 *
 * 总结到目前为止给成员变量赋值的方法：
 *  1，直接在声明的时候 显式的初始化赋值
 *  2，构造器赋值
 *  3，构造代码块赋值
 *
 *  首先我们看1，3的顺序
 *  通过大白 大黄的案例 能否说明构造代码块在显式赋值之后执行呢？
 *  我说是不能的，因为代码的顺序没有考虑
 *  我们发现，代码的书写顺序对1，3的顺序有显著影响，谁在下面，就后执行谁，属性的结果就是后面那个
 *  所以强调一下：
 *      应该把构造代码块写在变量的声明之后，首先如果写在前面就出现了变量没有声明却赋值的奇怪现象
 *      并且我们发现显式赋值和代码块谁在下面谁后执行，这种顺序影响了代码的结果，我们希望代码是机械的
 *      不受外界影响
 *      只有一种情况下你能这么写：你作为面试官，要去考面试者了，于是你这么写
 *
 * 后面再看2的执行顺序：
 * 我们发现构造器在后面执行
 * 注意任何时候，构造器都是最后执行的
 * 也就是说，用构造器创建对象，构造器中写的属性是绝对可信的，你写什么，结果就是什么。而构造代码块和显式的赋值都是会被构造器给覆盖掉的
 *
 * 总结：
 * new过程当中，构造代码块，显式赋值，构造器的执行顺序：
 * 1，如果构造器的第一行使用了this调用了别的构造器，那么程序会先跳到this构造器，但是不会执行this构造器代码
 * 2,接下来：
 *  先默认初始化所有的成员变量
 *  接下来按照上下的顺序执行显式赋值和构造代码块
 *  接下来再执行this构造器
 *  最后执行那个被调用的构造器
 *
 *  这里我们缺少一点知识，现在先记住，明天讲原理
 *
 *  构造代码块的作用：
 *      根据构造代码块随着构造方法的执行而执行，并且永远是先于构造器执行
 *      提取出所有构造器都会调用的代码，放入构造代码块中，这样每创建对象都会执行
 *      实际上这种用途很多，比如说你要初始化一个成员变量，但是不要一条语句就能得到结果
 *
 */
public class Demo {
    public static void main(String[] args) {
       /* Cat cat = new Cat();
        System.out.println(cat.name);*/
       //使用name的构造器创建对象
       // Cat c = new Cat(1,"小绿");//3
        //System.out.println(c.name);

        //Person p = new Person(1,"张三");
        System.out.println(Cat.var);
    }
}
class Cat {
    public Cat(String name) {
        this.name = name;
        System.out.println("this");
    }
    //奇怪的操作，name好像还没有声明，就进行了赋值，但是语法允许我们这么做
    {
        name = "大黄";//2
        System.out.println("大黄");
        //构造代码块是创建对象时用的，这个时候类加载肯定结束了
        //所以这个时候var已经存在了 那么我给它赋值是可以的
        //但是这种赋值 必须要创建对象才生效
        //那么如果我想要不创建对象，也能赋值，怎么办？
        //用静态代码块
        var = 1;
    }
    int age;
    String name = "大白"; //1
    static int var;
    public Cat() {
    }

    public Cat(int age,String name) {
        this(name);
        System.out.println("this之后");
        this.age = age;
    }
}

class Person{
    int age;
    String name;
    {
        //模拟每次创建对象都会执行的语句
        System.out.println("你创建了Person对象");
    }

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public Person(String name) {
        this.name = name;
    }

    public Person(int age) {
        this.age = age;
    }

    public Person() {
    }
}
